<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>build-your-own-react/</title>
</head>

<body>
  <div id="test"></div>
  <script>
    var virdom = {
      type: "h1",
      props: {
        title: "hello",
        children: "Hello world",
      },
    };

    var createTextElement = (text) => ({
      type: "TEXT_ELEMENT",
      props: {
        nodeValue: text,
        children: [],
      },
    });

    var createElement = (type, props, ...children) => ({
      type: type,
      props: {
        ...props,
        children: children.map((child) => {
          if (typeof child === "object") {
            return child;
          } else {
            return createTextElement(child);
          }
        }),
      },
    });

    const didReact = {
      createElement,
      render,
    };

    const renderEle = didReact.createElement(
      "div",
      { id: "app", title: "123" },
      createElement("span", null, "hello123"),
      "world"
    );

    /*       
    function render(ele, body) {
      const dom =
        ele.type === "TEXT_ELEMENT"
          ? document.createTextNode("")
          : document.createElement(ele.type);
      Object.keys(ele.props)
        .filter((item) => item !== "children")
        .forEach((name) => {
          dom[name] = ele.props[name];
        });

      ele.props.children.map((child) => {
        render(child, dom);
      });

      body.appendChild(dom);
    }
*/

    function craeteDom(fiber) {
      const dom =
        fiber.type === "TEXT_ELEMENT"
          ? document.createTextNode("")
          : document.createElement(fiber.type);

      Object.keys(fiber.props)
        .filter((item) => item !== "children")
        .forEach((name) => {
          dom[name] = fiber.props[name];
        });
      return dom;
    }

    function commitRoot() {
      commitWork(wipRoot.child);
      currentRoot = wipRoot;
      wipRoot = null;
    }

    function commitWork(fiber) {
      if (!fiber) {
        return;
      }
      const domParent = fiber.parent.dom;
      domParent.appendChild(fiber.dom);
      commitWork(fiber.child)
      commitWork(fiber.sibling)
    }

    // 4.渲染和提交阶段      

    function render(element, container) {
      wipRoot = {
        dom: container,
        props: {
          children: [element]
        },
        alternate: currentRoot
      }
      nextUnitOfWork = wipRoot;
    }

    let wipRoot = null;
    let nextUnitOfWork = null;
    let currentRoot = null;

    didReact.render(renderEle, document.getElementById("test"));


    // 3.并发处理


    function workLoop(deadline) {
      let shouldYield = false;
      while (nextUnitOfWork && !shouldYield) {
        nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
        shouldYield = deadline.timeRemaining() < 1;
      }
      requestIdleCallback(workLoop);
    }

    if (!nextUnitOfWork && wipRoot) {
      commitRoot()
    }

    requestIdleCallback(workLoop);

    function performUnitOfWork(fiber) {
      // TODO
      if (!fiber.dom) {
        fiber.dom = craeteDom(fiber);
      }

      // if (fiber.parent) {
      //   fiber.parent.dom.appendChild(fiber.dom);
      // }

      const elements = fiber.props.chilren;
      if (fiber.child) {
        return filter.child
      }
      let nextFiber = fiber
      while (nextFiber) {
        if (nextFiber.sibling) {
          return nextFiber.sibling
        }
        nextFiber = nextFiber.parent;
      }
    }

    function reconcileChilren(wipFiber, elements) {

      let index = 0;
      let prevSibling = null;

      while (index < elements.length) {
        const element = elements[index];

        const newFiber = {
          type: element.type,
          props: element.props,
          parent: wipFiber,
          dom: null,
        };

        if (index === 0) {
          wipFiber.child = newFiber;
        } else {
          prevSibling.sibling = newFiber;
        }

        prevSibling = newFiber;
        index++;
      }
    }




      // var ele = document.createElement(virdom.type);
      // ele["title"] = virdom.props.title;
      // var text = document.createTextNode("");
      // text["nodeValue"] = virdom.props.children;
      // ele.appendChild(text);
      // document.body.appendChild(ele);
  </script>
</body>

</html>